# coding:utf-8
# writingtime: 2022-7-29

class RandomData():
    def __init__(self, expe_n = 5, plan_n = 5, attr_n =5 ,
                 data=[], expert=[],attri=[], *waste1, **waste2):
        """
            function : 初始化函数
        """
        self.data = data
        self.expert = expert
        self.attri = attri
        # 随机数时候用的
        self.size = [expe_n, plan_n, attr_n]

        # 初始化的评价指标
        # 数值评分映射的区间值广义正交模糊数
        # 不要出现 0.0 和 1.0 对于 log，x**q 来说会出现 math domain 的错误
        self.data_dict = {
            0: ([0.01, 0.10], [0.90, 0.99]),
            1: ([0.10, 0.20], [0.80, 0.90]),
            2: ([0.20, 0.35], [0.65, 0.80]),
            3: ([0.35, 0.45], [0.55, 0.65]),
            4: ([0.45, 0.55], [0.45, 0.55]),
            5: ([0.55, 0.65], [0.35, 0.45]),
            6: ([0.65, 0.80], [0.20, 0.35]),
            7: ([0.80, 0.90], [0.10, 0.20]),
            8: ([0.90, 0.95], [0.05, 0.10]),
            9: ([0.95, 0.99], [0.01, 0.05])
        }
        # 数字评分代表的意思
        self.meaning_dict = {
            0: "Certainly low important (CLI)",
            1: "Very low important(VLI)",
            2: "Low important(LI)",
            3: "Below average important (BAI)",
            4: "Average important(AI)",
            5: "Above average important(AAI)",
            6: "High important(HI)",
            7: "Very high important(VHI)",
            8: "Certainly high important(CHI)",
            9: "More Certainly high important(MCHI)",
            10: "Exactly equal(EE)"
        }
        # 评级的分数区间
        self.data_assess_value = []

        # 默认使用均匀分布分布和接近的权重
        self.get_Uniform_random(show_distri=False)

    # 使用随机生成的数据集
    # 对随机生成矩阵，的，功能函数
    def array_trans_fuzzy(self, rand_array):
        """
            function    : 将随机的生成的 m,n,k 的矩阵 —— 数值为 [0, 9] —— 因为评分范围 [0,9]
            rand_array  : m x n x k 的矩阵 —— 元素为实数的
            process     : 过程为，将矩阵中数做边界处理 小于0转为 0.00111 大于9的转为 8.99999
                          以 1.2 为例子, 先向下取整为 1 做 base, 评分值 1 对应
                          评分值 1 对应 ([0.10, 0.20], [0.80, 0.90])
                          评分值 2 对应  ([0.20, 0.35], [0.65, 0.80]),
                          算两个评分对模糊每个 u，v 之间 差值 dis(u1,u2,v1,v2)
                          用 1.2-1=0.2 做权重, 计算结果值
                          以 u1 为例，u1 = 0.2*(0.2-0.1) + 0.1
                          以 v1 为例，v1 = 0.2*(0.65-0.80) + 0.80
            return      :  m x n x k 的 元素为区间值广义正交模糊数 的服从某种分布的数据集
        """
        # 导入库
        import numpy as np

        # 传入容器转为 np 的矩阵
        rand_array = np.array(rand_array)
        # print("befor time :\n", rand_array>9)
        max = np.max(rand_array)
        rand_array = rand_array / max * 9
        # print("after time :\n", rand_array>9)

        # 做个溢出处理处理
        rand_array[rand_array <= 0] = 0.01111
        rand_array[rand_array >= 9] = 8.99999
        # 做一个向下取整的处理
        temp_array = np.floor(rand_array)

        # 矩阵元素转换
        result_array = []   # list 空容器
        for i in range(len(rand_array)):  # 变量每个元素
            result_array.append([])
            for j in range(len(rand_array[i])):
                result_array[i].append([])
                for k in range(len(rand_array[i][j])):
                    # 开始转换
                    # 去 base 和 up=base+1 对应的值和模糊数
                    base = temp_array[i][j][k]
                    # 获取差值
                    # temp_array 由 rand_array 向下取整得到的 , 所以差值为 [0, 1] ——> 完成归一化
                    dist = rand_array[i][j][k] - temp_array[i][j][k]
                    element_bs = self.data_dict[base]
                    element_up = self.data_dict[base + 1]
                    # 加权换算模糊数的 隶属度区间 和 费隶属度区间
                    u_bs_f, u_bs_r, v_bs_f, v_bs_r = *element_bs[0], *element_bs[1]
                    u_up_f, u_up_r, v_up_f, v_up_r = *element_up[0], *element_up[1]
                    # method = lambda base, up , dist : round((up-base)*dist+base, 5)
                    # u_re_f = method(u_bs_f, u_up_f, dist)
                    u_re_f = round((u_up_f - u_bs_f) * dist + u_bs_f, 5)
                    u_re_r = round((u_up_r - u_bs_r) * dist + u_bs_r, 5)
                    v_re_f = round((v_up_f - v_bs_f) * dist + v_bs_f, 5)
                    v_re_r = round((v_up_r - v_bs_r) * dist + v_bs_r, 5)
                    # 生成结果值，并加入到原型实数对应位置
                    result = ([u_re_f, u_re_r], [v_re_f, v_re_r])
                    result_array[i][j].append(result)
        return result_array

    def show_distribution(self, rand_array, showimg = True, saveimg=False, savepath="distribute.jpeg"):
        """
            function    : 将随机的生成的 m,n,k 的矩阵 —— 绘制成 3d 分布图
            rand_array  : m x n x k 的矩阵 —— 元素为实数的

        """
        import matplotlib.pyplot as plt
        import numpy as np
        # 初始化画布
        fig = plt.figure(figsize=(10, 8))
        ax = fig.add_subplot(projection="3d")

        ax.set_xlabel("exper")
        ax.set_ylabel("project")
        ax.set_zlabel("attribute")

        for i in range(len(rand_array)):
            x = np.array([i]*len(rand_array[i]))
            for j in range(len(rand_array[i])):
                y = np.arange(len(rand_array[i][j]))
                ax.scatter(x, y, rand_array[i][j], marker='^')
        if saveimg:
            plt.savefig(savepath)
        if showimg:
            plt.show()
        plt.close(fig)
        pass

    def show_array(self, array):
        """
            function: 描述输出矩阵
        """
        for index, items in enumerate(array):
            print("第{:}位专家对每个方案每个属性判断:".format(str(index + 1)))
            for item in items:
                print(item)

    # 依据概率分布
    """高斯分布"""
    def get_Gaussian_random(self, mean=4.5, std=3, show_distri = False, size=[]):
        """
            function    : 随机生成服从正态分布的
            mean        : 正态分布的均值  —— 设置在数据范围中间
            std         : 正态分布的标准差 —— 适宜即可
            show_distri : 是否需要绘制三维散点图
            get_return  : 是否需要返回结果
            size        : 数据大小
            return      : m x n x k 的 元素为区间值广义正交模糊数决策集合，是服从某种分布的数据集
        """
        import numpy as np
        # 对size进行初始化
        if len(size):
            size=size
        else:
            size = self.size

        # 生成正态分布的数据 —— 生成数值为 [0,9]，最好
        rand_array = np.random.normal(mean, std, size)
        # print(rand_array)

        # 绘制成 3d 散点图
        if show_distri:
            self.show_distribution(rand_array, show_distri)

        # 将矩阵转为模糊数矩阵
        result_array = self.array_trans_fuzzy(rand_array)
        # 替换数据
        self.data = result_array
        self.data_assess_value = rand_array

        return result_array

    """均值分布"""
    def get_Uniform_random(self, low=0, high=9, show_distri=False, size=[]):
        """
            function    : 随机生成服从均值分布的
            low         : 均匀分布的最低值 —— 似乎没包含
            high        : 均匀分布的最高值 —— 似乎没包含
            show_distri : 是否需要绘制三维散点图
            get_return  : 是否需要返回结果
            return      : m x n x k 的 元素为区间值广义正交模糊数决策集合，是服从某种分布的数据集
        """
        import numpy as np

        # 对size进行初始化
        if len(size):
            size = size
        else:
            size = self.size

        # 均匀分布 生成shape为size 的随机矩阵
        rand_array = np.random.uniform(low, high, size)
        # print(rand_array) # 测试

        # 将矩阵转为模糊数矩阵
        result_array = self.array_trans_fuzzy(rand_array)
        # 替换数据
        self.data = result_array
        self.data_assess_value = rand_array

        # 绘制分布图
        if show_distri:
            self.show_distribution(rand_array,show_distri)

        return result_array

    """泊松分布"""
    def get_Poisson_random(self, mean=4, show_distri=False, size=[]):
        """
            function     : 随机生成服从泊松分布的
            mean         : 正态分布的均值  —— 设置在数据范围中间
            digit        : 将区间值扩大倍数
            show_distri  : 是否需要绘制三维散点图
            get_return   : 是否需要返回结果
            return       : m x n x k 的 元素为区间值广义正交模糊数决策集合，是服从某种分布的数据集
        """
        import numpy as np
        # size = [10, 10, 10]
        # 对size进行初始化
        if len(size):
            size = size
        else:
            size = self.size
        # 生成正态分布的数据 —— 生成数值为 [0,9]，最好
        rand_array = np.random.poisson(lam=mean, size=size)   # lam为λ size为k

        # print(rand_array)

        # 绘制成 3d 散点图
        if show_distri:
            self.show_distribution(rand_array, show_distri)

        # 将矩阵转为模糊数矩阵
        result_array = self.array_trans_fuzzy(rand_array)
        # 替换数据
        self.data = result_array
        self.data_assess_value = rand_array

        return result_array

    """指数分布"""
    def get_Exponential_random(self, scale=4, show_distri=False, size=[]):
        """
            function    : 随机生成服从指数分布的多属性决策群
            return      : m x n x k 的 元素为区间值广义正交模糊数决策集合，是服从某种分布的数据集
        """
        import numpy as np
        # size = [10, 10, 10]
        # 对size进行初始化
        if len(size):
            size = size
        else:
            size = self.size

        # 生成正态分布的数据 —— 生成数值为 [0,9]，最好
        rand_array = np.random.exponential(scale=scale, size=size)  # lam为λ size为k

        # 绘制成 3d 散点图
        if show_distri:
            self.show_distribution(rand_array, show_distri)

        # 将矩阵转为模糊数矩阵
        result_array = self.array_trans_fuzzy(rand_array)
        # 替换数据
        self.data = result_array
        self.data_assess_value = rand_array

        return result_array

    """正态分布"""
    def get_Lognormal_random(self, mean=2, signma=1, show_distri=False, size=[]):
        """
            function    : 随机生成服从对数正态分布的多属性决策群
            return      : m x n x k 的 元素为区间值广义正交模糊数决策集合，是服从某种分布的数据集
        """
        import numpy as np
        # size = [10, 10, 10]
        # 对size进行初始化
        if len(size):
            size = size
        else:
            size = self.size
        # 生成对数正态分布的数据 —— 生成数值为 [0,9]，最好
        rand_array = np.random.lognormal(mean=mean, sigma=signma, size=size)  # 期望、标准差、 size为k

        # 绘制成 3d 散点图
        if show_distri:
            self.show_distribution(rand_array, show_distri)

        # 将矩阵转为模糊数矩阵
        result_array = self.array_trans_fuzzy(rand_array)
        # 替换数据
        self.data = result_array
        self.data_assess_value = rand_array

        return result_array

if __name__=='__main__':
    data=RandomData().get_Gaussian_random()
    # print(Distribute().get_Gaussian_random.__class__)
    # for i in (data):
    #     for j in i:
    #         print(j)


